<?php

namespace app\common\middleware;

use app\common\component\ErrorCode;
use \app\common\component\Redis;

/**
 * 截流中间件
 * Class ThrottleMiddleware
 * @package app\common\middleware
 */
class ThrottleMiddleware
{
    /** @var null 单例 */
    public static $instance = null;
    /** @var array 列表数据，忽略限制 */
    public static $ignoreAction = ['listelasticsearch'];

    /**
     * 构造函数
     * ThrottleMiddleware constructor.
     */
    private function __construct()
    {}

    /**
     * 单例
     * @param bool $newInstance
     * @return null|static
     */
    public static function getInstance($newInstance = false)
    {
        if (is_null(static::$instance) || $newInstance) {
            self::$instance = new static();
        }

        return self::$instance;
    }

    /**
     * 将ip转为10进制
     * @param $ip
     * @return float|int|string
     */
    public function ipToLong($ip)
    {
        $ip = explode('.', $ip);
        $ip = array_reverse($ip);//数组反转
        $r = 0;
        for($i=0,$j=count($ip); $i<$j; $i++){
            $r += $ip[$i] * pow(256, $i);
        }
        $r = sprintf("%u", $r);
        return $r;
    }

    /**
     * 每日限流的(ip限流)
     * ajax访问限流
     * @param $request
     */
    public function accessLimit($request)
    {
        $controllerName = $request->controller();
        /** ajax访问进行限流 */
        if(isset($_SERVER["HTTP_X_REQUESTED_WITH"]) && strtolower($_SERVER["HTTP_X_REQUESTED_WITH"])=="xmlhttprequest" && !in_array($controllerName, self::$ignoreAction)) {
            $moduleName = $request->module();
            $actionName = $request->action();
            $ip = isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER["REMOTE_ADDR"] : 0;
            $ipToLong = $this->ipToLong($ip);
            $suffix = $moduleName . '::' . $controllerName . '::' . $actionName . '::' . $ipToLong;
            $redisKey = Redis::getInstance()->getRedisName(Redis::ACCESS_THROTTLE_PREFIX, $suffix);
            if (Redis::getInstance()->incr($redisKey) > 50) {
                throw new \Exception('您的ip已经达到每日访问此功能次数限制', ErrorCode::RESPONSE_FREQUENTLY);
            }

            $current = time();
            Redis::getInstance()->expire($redisKey, TODAY_TIMESTAMP + 86400 - $current);
        }
    }

    // 频率限制(初步思路: redis的有序列表)

}